package jee.boot.common.service;

import jee.boot.common.basic.ServiceException;
import jee.boot.entity.system.Filter;
import jee.boot.common.utils.DateUtils;
import jee.boot.common.utils.IdGenerate;
import jee.boot.common.utils.StringUtils;
import jee.boot.entity.system.SerialNumber;
import jee.boot.entity.system.SerialNumberFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

@Service
public class SerialNumberHandler {
    public static final SerialNumberFormat DEFAULT_SERIAL_NUMBER_FORMAT_HOUR = new SerialNumberFormat("hour");
    public static final SerialNumberFormat DEFAULT_SERIAL_NUMBER_FORMAT_DAY = new SerialNumberFormat("day");
    public static final SerialNumberFormat DEFAULT_SERIAL_NUMBER_FORMAT_MONTH = new SerialNumberFormat("month");
    public static final SerialNumberFormat DEFAULT_SERIAL_NUMBER_FORMAT_YEAR = new SerialNumberFormat("year");

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private SerialNumberFormatService serialNumberFormatService;
    @Autowired
    private SerialNumberService serialNumberService;

    /**
     * 获取下一个序列号
     *
     * @return
     */
    public String getSerialNumber(String type, String category, SerialNumberFormat serialNumberFormat) {
        // 尝试3次
        int retry = 3;
        for (int i = 0; i < retry; i++) {
            try {
                return getNewSerialNumber(type, category, serialNumberFormat);
            } catch (Exception e) {
                logger.warn("尝试获取序列号第" + i + "次失败");
            }
        }
        return null;
    }

    /**
     * 同步方法,获取下一个序列号
     *
     * @return
     */
    private synchronized String getNewSerialNumber(String type, String category, SerialNumberFormat serialNumberFormat) {
        SerialNumberFormat numberFormat = serialNumberFormatService.get(serialNumberFormat);
        if (numberFormat != null) {
            StringBuilder sb = new StringBuilder();
            String prefix = numberFormat.getPrefix();
            int serialLength = numberFormat.getSerialLength();
            String dateFormat = numberFormat.getDateFormat();
            String dateTime = DateUtils.formatDate(new Date(), dateFormat);
            sb.append(prefix).append(dateTime);
            SerialNumber query = new SerialNumber();
            query.addFilter(new Filter("type", "=", type));
            query.addFilter(new Filter("category", "=", category));
            List<SerialNumber> list = serialNumberService.findList(query);

            SerialNumber serialNumber;
            // 如果存在则已经产生过当前类型的序列号,则直接使用序列号队列
            if (list != null && !list.isEmpty()) {
                serialNumber = list.get(0);
                serialNumber.setOldVersion(serialNumber.getVersion());
                // 如果数据周期一样,则直接更新即可
                if (StringUtils.equals(serialNumber.getDataCycle(), dateTime)) {
                    serialNumber.setVersion(serialNumber.getVersion() + 1);
                    serialNumber.setSerialNumber(getNextSerialNumber(sb.toString(), serialLength, serialNumber.getSerialNumber()));
                } else {
                    //如果数据周期不一样,则需要重新记录周期
                    serialNumber.setVersion(0);
                    serialNumber.setDataCycle(dateTime);
                    serialNumber.setSerialNumber(getNextSerialNumber(sb.toString(), serialLength, null));
                }
                boolean update = serialNumberService.checkAndUpdateVersionAndStatus(serialNumber);
                if (update) {
                    return serialNumber.getSerialNumber();
                } else {
                    throw new ServiceException();
                }

            } else {
                //没有历史序列号,则使用新的序列号队列
                serialNumber = new SerialNumber();
                serialNumber.setType(type);
                serialNumber.setCategory(category);
                serialNumber.setDataCycle(dateTime);
                serialNumber.setVersion(0);
                serialNumber.setSerialNumber(getNextSerialNumber(sb.toString(), serialLength, null));
                serialNumberService.save(serialNumber);
                return serialNumber.getSerialNumber();
            }
        }
        return null;
    }

    /**
     * 读取下一个序列号
     *
     * @param prefix          前缀
     * @param serialLength    自增号长度
     * @param preSerialNumber 上一个序列号
     */
    private String getNextSerialNumber(String prefix, int serialLength, String preSerialNumber) {
        // 如果存在上一个序列号,直接递增
        if (StringUtils.isNotBlank(preSerialNumber)) {
            return IdGenerate.nextCode(preSerialNumber);
        }
        // 如果没有上一个序列号,则从1开始
        return prefix + StringUtils.leftPad("1", serialLength, "0");
    }

}
